package opensslCore;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

/*
 * @info process using openSSL interaction with pipes
 * @author Arnaud Sansig
 */
public class ProcessHandler {

	private boolean isRunning;				/*boolean used to stop the process*/
	private PipeReader pipeReader;				/*Reading continuously from STDIN pipe*/
	private PipeError pipeError;
	private BufferedWriter writer;
	private BufferedReader reader;
	private BufferedReader error;
	private InputStream stdout;
	private OutputStream stdin;
	private InputStream stderr;
	private java.lang.Process process;
	
	/*
	 * @info Default constructor
	 */
	public ProcessHandler() {
		/*Some declarations*/
		java.lang.Runtime ct;							
		
		this.isRunning=true;
		
		try
		{
			/*Execute a new process*/
			ct= java.lang.Runtime.getRuntime();
			process = ct.exec("openssl");
			
			/*stdin from process*/
			this.stdin = process.getOutputStream ();
			/*stderr from process*/
			this.stderr = process.getErrorStream();
			/*stdout from process*/
			this.stdout = process.getInputStream ();
			
			/*Redirect : read from process stdout*/
			this.reader = new BufferedReader (new InputStreamReader(this.stdout));
			/*Redirect : error from process stdout error*/
			this.error = new BufferedReader (new InputStreamReader(this.stderr));
			/*Redirect : write to process stdin*/
			this.writer = new BufferedWriter(new OutputStreamWriter(this.stdin));
			
			/*Execute new thread => read continuous data from process stdout*/
			this.pipeReader=new PipeReader(this.reader);
			this.pipeError=new PipeError(this.error);
			
			new Thread(this.pipeReader).start();
			new Thread(this.pipeError).start();
		}
		catch(Exception ex)
		{
			System.out.println("Exception ProcessHandler::run()");
		}
	}
	
	/*
	 * @info Write to openSSL stdin
	 * @param data data to send
	 * @throws exception if the pipe is broken
	 */
	public void writeOpenSSL(String data) {
		if(this.isRunning)
		{
			try
			{
				data+="\n";
				this.writer.write(data);
				this.writer.flush();
			}
			catch(Exception ex)
			{
				System.out.println("Exception ProcessHandler::writeOpenSSL()");
			}
		}
	}
	
	/*
	 * @info is the process running at this time?
	 * @return boolean
	 */
	public boolean isRunning() {
		return this.isRunning;
	}
	
	/*
	 * @info Close all pipes
	 */
	public void close() {
		try
		{
			if(this.isRunning)
			{
				this.pipeReader.stopReading();
				this.pipeError.stopReading();
				
				this.writer.write("exit\n");
				this.writer.flush();
				this.process.waitFor();
				
				this.error.close();
				this.reader.close();
				this.writer.close();
				
				this.isRunning=false;
				
				this.stdin.close();
				this.stdout.close();
				this.stderr.close();
			}
		}
		catch(Exception ex)
		{
			System.out.println("Exception ProcessHandler::close()");
		}
	}
}